package wechatbot

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"time"

	"gitee.com/kvenli/wechatbot/message"
	"gitee.com/kvenli/wechatbot/response"
)

const (
	Timeout = 5 * time.Second
	Webhook = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send"
)

type Bot struct {
	Key    string
	Client *http.Client
	message.IMessage
}

func NewBot(key string) *Bot {
	return &Bot{
		Key: key,
	}

}

// 发送消息
func (bot *Bot) Send(msg message.IMessage) (*response.Response, error) {
	var (
		data   []byte
		result []byte
		err    error
	)
	if msg.GetType() == "file" {
		file, ok := msg.(*message.File)
		if ok {
			if result, err = bot.upload(file.FileName); err != nil {
				fmt.Println("upload has error")
				return nil, err
			}
			var resp = new(response.Response)
			if err = json.Unmarshal(result, &resp); err != nil {
				return nil, err
			}
			if resp.Code != 0 {
				return resp, nil
			}
			file.FileBody.MediaId = resp.MediaID
			msg = file
		}
	}

	if data, err = json.Marshal(msg); err != nil {
		return nil, err
	}

	if result, err = bot.send(data); err != nil {
		return nil, err
	}
	// fmt.Println(string(result))
	var resp = new(response.Response)
	if err = json.Unmarshal(result, &resp); err != nil {
		return nil, err
	}
	return resp, nil
}

func (bot *Bot) send(data []byte) ([]byte, error) {
	var (
		req *http.Request
		err error
	)
	if req, err = bot.buildSendRequest(data, http.Header{}); err != nil {
		return nil, err
	}

	if bot.Client == nil {
		bot.setDefaultClient()
	}
	var resp *http.Response
	if resp, err = bot.Client.Do(req); err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("error http code: %d", resp.StatusCode)
	}

	var body []byte
	if body, err = io.ReadAll(resp.Body); err != nil {
		return nil, err
	}
	return body, err
}

func (bot *Bot) upload(filename string) ([]byte, error) {
	var (
		req *http.Request
		err error
	)
	if req, err = bot.buildUploadFileRequest(filename, http.Header{}); err != nil {
		return nil, err
	}

	if bot.Client == nil {
		bot.setDefaultClient()
	}
	var resp *http.Response
	if resp, err = bot.Client.Do(req); err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("error http code: %d", resp.StatusCode)
	}

	var body []byte
	if body, err = io.ReadAll(resp.Body); err != nil {
		return nil, err
	}
	//fmt.Println("resp", string(body))
	return body, err
}

// build a http request
func (bot *Bot) buildSendRequest(data []byte, header http.Header) (*http.Request, error) {
	var (
		url *url.URL
		err error
	)
	if url, err = url.Parse(Webhook); err != nil {
		return nil, err
	}
	query := url.Query()
	query.Set("key", bot.Key)
	url.RawQuery = query.Encode()
	// fmt.Println(url.String())

	var req *http.Request
	if req, err = http.NewRequest("POST", url.String(), bytes.NewReader(data)); err != nil {
		return nil, err
	}

	header.Set("Content-Type", "application/json;charset=utf-8")
	req.Header = header

	return req, nil
}

// default http client
func (bot *Bot) setDefaultClient() *Bot {
	bot.Client = &http.Client{Timeout: Timeout}
	return bot
}

func (bot *Bot) buildUploadFileRequest(filename string, header http.Header) (*http.Request, error) {
	var (
		url *url.URL
		buf bytes.Buffer
		req *http.Request
		err error
	)
	multipartWriter := multipart.NewWriter(&buf)

	if url, err = url.Parse(Webhook); err != nil {
		return nil, err
	}

	//关键的一步操作
	fileWriter, err := multipartWriter.CreateFormFile("file", filepath.Base(filename))
	if err != nil {
		fmt.Println("error writing to buffer")
		return nil, err
	}

	//打开文件句柄操作
	fileinfo, err := os.Stat(filename)
	if err != nil {
		fmt.Println("error opening file")
		return nil, err
	}
	file, err := os.Open(filename)
	if err != nil {
		fmt.Println("error opening file")
		return nil, err
	}
	defer file.Close()

	//iocopy
	_, err = io.Copy(fileWriter, file)
	if err != nil {
		return nil, err
	}
	multipartWriter.Close()

	url.Path = "cgi-bin/webhook/upload_media"
	query := url.Query()
	query.Set("key", bot.Key)
	query.Set("type", "file")
	//query.Set("debug", "1")
	url.RawQuery = query.Encode()

	if req, err = http.NewRequest("POST", url.String(), &buf); err != nil {
		return nil, err
	}
	header.Set("Content-Type", multipartWriter.FormDataContentType())
	header.Set("Content-Length", fmt.Sprint(fileinfo.Size()))
	req.Header = header
	return req, nil
}

// func postFile(filename string, targetUrl string) error {
// 	buf := &bytes.Buffer{}
// 	multipartWriter := multipart.NewWriter(buf)

// 	//关键的一步操作
// 	fileWriter, err := multipartWriter.CreateFormFile("file", filename)
// 	if err != nil {
// 		fmt.Println("error writing to buffer")
// 		return err
// 	}

// 	//打开文件句柄操作
// 	file, err := os.Open(filename)
// 	if err != nil {
// 		fmt.Println("error opening file")
// 		return err
// 	}
// 	defer file.Close()

// 	//iocopy
// 	_, err = io.Copy(fileWriter, file)
// 	if err != nil {
// 		return err
// 	}
// 	multipartWriter.Close()

// 	contentType := multipartWriter.FormDataContentType()

// 	resp, err := http.Post(targetUrl, contentType, buf)
// 	if err != nil {
// 		return err
// 	}
// 	defer resp.Body.Close()
// 	resp_body, err := ioutil.ReadAll(resp.Body)
// 	if err != nil {
// 		return err
// 	}
// 	fmt.Println(resp.Status)
// 	fmt.Println(string(resp_body))
// 	return nil
// }
